﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SharpSoft.IO.Ports
{

    /**
     * 2022 01 09
    */
    using System.IO.Ports;
    using System.Threading;


    public delegate void InputChangedEventHandler(int controllerAddress, int group, int inputLine, bool OnOrOff);
    /// <summary>
    /// JMDM_COM控制器
    /// </summary>
    public class JMDM_COMHelper : IDisposable
    {
        public class Result
        {
            public int ControllerAddress { get; set; }

            public int Group { get; set; }

            public bool[] Status { get; set; }

        }
        SerialPort sp;
        Thread thread1, thread2;
        private Dictionary<long, bool[]> status;
        public JMDM_COMHelper(string comport, int baudrate = 9600)
        {
            status = new Dictionary<long, bool[]>();
            sp = new SerialPort(comport, baudrate);

        }
        /// <summary>
        /// 提供的控制器数量
        /// </summary>
        public int ControllerCount { get; set; } = 1;


        void threadWhile2()
        {
            while (isruning)
            {
                Thread.Sleep(200);
                try
                {
                    for (int cindex = 0; cindex < ControllerCount; cindex++)
                    {
                        switch (UsedDevice)
                        {
                            case DeviceType.JMDMCOM4DI2DOMR://四路控制器
                                Request(cindex, 6);//四路组号固定用6
                                break;
                            case DeviceType.JMDMCOM20DI://20路控制器
                                for (int group = 1; group < 5; group++)
                                {//20路控制器为4个分组
                                    Request(cindex, group);
                                    Thread.Sleep(100);
                                }

                                break;
                            default:
                                break;
                        }

                    }
                }
                catch (Exception ex)
                {

                }

            }


        }
        void threadWhile1()
        {
            while (isruning)
            {
                Thread.Sleep(20);
                try
                {

                    var str = sp.ReadTo(")");
                    //sp.DiscardInBuffer();
                    var res = receive(str);
                    if (res != null)
                    {
                        try
                        {
                            StatusReceive(res);
                        }
                        catch (Exception ex)
                        {
                            //忽略回掉中的异常
                        }

                    }
                }
                catch (Exception ex)
                {

                }

            }


        }

        void StatusReceive(Result result)
        {
            long key = ((long)result.ControllerAddress << 32) + result.Group;
            if (status.ContainsKey(key))
            {
                CompaStatus(key, status[key], result.Status);
                status[key] = result.Status;
            }
            else
            {
                status.Add(key, result.Status);
                bool[] sts = new bool[result.Status.Length];
                for (int i = 0; i < result.Status.Length; i++)
                {
                    sts[i] = !result.Status[i];//首次检测到状态时将当前状态取反，总是触发状态改变事件
                }
                CompaStatus(key, sts, result.Status);
            }

            StatusReceived?.Invoke(result);
        }
        /// <summary>
        /// 比较收到的输入点状态
        /// </summary>
        /// <param name="key"></param>
        /// <param name="oldstatus"></param>
        /// <param name="newstatus"></param>
        void CompaStatus(long key, bool[] oldstatus, bool[] newstatus)
        {
            try
            {
                int cadd = (int)(key >> 32);
                int group = (int)(key - cadd);

                for (int i = 0; i < newstatus.Length; i++)
                {
                    var newi = newstatus[i];
                    var oldi = false;
                    if (i < oldstatus.Length)
                    {
                        oldi = oldstatus[i];
                    }
                    if (newi != oldi)
                    {
                        InputChanged?.Invoke(cadd, group, i, newi);
                    }
                }

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 接收到新的输入点状态
        /// </summary>
        public event Action<Result> StatusReceived;
        /// <summary>
        /// 输入点状态有改变
        /// </summary>
        public event InputChangedEventHandler InputChanged;

        Result receive(string str)
        {
            string cmdstart = "I(";
            int index = str.IndexOf(cmdstart);
            if (index < 0)
            {//无效的数据
                return null;
            }
            var val = str.Substring(index + cmdstart.Length);
            var vals = val.Split(new char[] { ',' });
            Result res = new Result()
            {
                ControllerAddress = int.Parse(vals[0]),
            };
            string sts;
            if (vals.Length == 3)
            {//有三个数据，第二个是分组号
                res.Group = int.Parse(vals[1]);//组号
                sts = vals[2];
            }
            else if (vals.Length == 2)
            {//有两个数据，没有分组号
                res.Group = 0;
                sts = vals[1];
            }
            else
            {
                sts = vals[vals.Length - 1];
            }


            List<bool> l = new List<bool>(5);
            foreach (var c in sts)
            {
                if (c == '1')
                {
                    l.Add(true);
                }
                else
                {
                    l.Add(false);
                }
            }
            res.Status = l.ToArray();
            return res;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="controllerAddress">控制器地址</param>
        /// <param name="group">组号(01-04)</param>
        public void Request(int controllerAddress, int group = 1)
        {
            var cmd = $"O({controllerAddress:00},{group:00},1)E";
            sp.Write(cmd);
        }

        bool isruning = false;
        public void Open()
        {
            sp.Open();
            isruning = true;
            thread1 = new Thread(threadWhile1);
            thread1.Start();
            thread2 = new Thread(threadWhile2);
            thread2.Start();
        }

        public void Close()
        {
            isruning = false;
            status?.Clear();
            status = null;
            sp?.Close();
            sp = null;
        }

        public void Dispose()
        {
            sp.Dispose();
        }

        /// <summary>
        /// 使用的设备类型
        /// </summary>
        public DeviceType UsedDevice { get; set; } = DeviceType.JMDMCOM4DI2DOMR;

        public enum DeviceType
        {
            /// <summary>
            /// 4路输入2路输出
            /// </summary>
            JMDMCOM4DI2DOMR,

            /// <summary>
            /// 20路输入
            /// </summary>
            JMDMCOM20DI

        }
    }
}
